#pragma once
#include <iostream>
#include "Epoller.hpp"
#include "connection.hpp"

using namespace EpollModule;

class Reactor
{
    static const int gmaxevents = 32;
    static const int default_port = 8080;

public:
    Reactor()
        : _isruning(false), _epoller(std::make_shared<Epoller>())
    {
        _epoller->InitEpoll(); // 创建epoll模型
    }
    bool ExistsConnection(int sockfd)
    {
        auto it = _conns.find(sockfd);
        if (it == _conns.end())
            return false;
        else
            return true;
    }
    void RemoveConnection(int sockfd)
    {
        if(!ExistsConnection(sockfd))
        {
            return;
        }
        _epoller->DelEvent(sockfd); 
        _conns.erase(sockfd);
    }
    void AddConnection(Connection::ptr conn)
    {
        if (conn.get() == nullptr)
            return;
        if (ExistsConnection(conn->SockFd()))
            return;
        _conns.insert(std::make_pair(conn->SockFd(), conn)); // 用户层管理
        _epoller->AddEvent(conn->SockFd(), conn->Events());  // 内核层管理
    }
    void LoopOnce(int timeout)
    {
        int n = _epoller->EpollWait(_events, gmaxevents, timeout);
        for (int i = 0; i < n; i++)
        {
            int sockfd = _events[i].data.fd;
            uint32_t event = _events[i].events;
            // 转化为读写异常
            if (event & EPOLLERR)
            {
                event |= (EPOLLIN | EPOLLOUT);
            }
            // 连接被对方关闭
            if (event & EPOLLHUP)
            {
                event |= (EPOLLIN | EPOLLOUT);
            }
            if ((event & EPOLLIN) && ExistsConnection(sockfd))
            {
                if (_conns[sockfd]->_reader)
                {
                    _conns[sockfd]->_reader(_conns[sockfd]);
                }
            }
            if ((event & EPOLLOUT) && ExistsConnection(sockfd))
            {
                if (_conns[sockfd]->_sender)
                {
                    _conns[sockfd]->_sender(_conns[sockfd]);
                }
            }
        }
    }
    // 修改关心的模式
    void EnableReadWrite(int sockfd, bool reader, bool writer)
    {
        if (!ExistsConnection(sockfd))
            return;
        uint32_t events = (EPOLLET | (reader ? EPOLLIN : 0) | (writer ? EPOLLOUT : 0));
        _conns[sockfd]->SetEvent(events);   // 修改用户关心
        _epoller->ModEvent(sockfd, events); // 修改内核中的
    }
    void Loop()
    {
        _isruning = true;
        while (_isruning)
        {
            int timeout = -1;
            LoopOnce(timeout);
            PrintList();
        }
        _isruning = false;
    }
    
    void PrintList()
    {
        std::cout << "client list info : " << std::endl;
        for(auto itme: _conns)
        {
            std:: cout << "fd : " << itme.first << "  , ip: " << itme.second->_addr.ToString() << std::endl;
        }
    }

    ~Reactor()
    {
    }

private:
    bool _isruning;
    Epoller::ptr _epoller;
    struct epoll_event _events[gmaxevents];
    std::unordered_map<int, Connection::ptr> _conns;
};